// 版权归Go作者所有。版权所有。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

// go:build 386 | arm | mips | mipsle | wasm | wasm | |（ios和&arm64）
// /+build 386 arm mips mipsle wasm ios，arm64 

// wasm是一个被视为32位体系结构的页面
// 分配器，即使它有64位指针。这是因为任何wasm 
// 指针的前32位总是为零，因此有效堆地址
// 空间的大小只有2^32字节（请参阅heapdRbits）。

// ios/arm64被视为32位体系结构，用于
// 页分配器，即使它有64位指针和33位地址
// 空间（请参阅HeapArbits）。33位地址空间不能向上舍入到64位，因为有太多的摘要级别，无法仅容纳33位。

package runtime

import "unsafe"

const (
	// 基数树中的级别数。
	summaryLevels = 4

	// 用于测试的常数。
	pageAlloc32Bit = 1
	pageAlloc64Bit = 0

	// 表示所有索引到
	// 块映射的L1中所需的位数。
	// 
	// 有关详细信息，请参阅（*pageAlloc）.chunks。更新文件
	// 此编号应更改。
	pallocChunksL1Bits = 0
)

// 请参阅mpagealloc64bit.go中的注释。
var levelBits = [summaryLevels]uint{
	summaryL0Bits,
	summaryLevelBits,
	summaryLevelBits,
	summaryLevelBits,
}

// 请参阅mpagealloc64bit.go中的注释。
var levelShift = [summaryLevels]uint{
	heapAddrBits - summaryL0Bits,
	heapAddrBits - summaryL0Bits - 1*summaryLevelBits,
	heapAddrBits - summaryL0Bits - 2*summaryLevelBits,
	heapAddrBits - summaryL0Bits - 3*summaryLevelBits,
}

// 请参阅mpagealloc64bit.go中的注释。
var levelLogPages = [summaryLevels]uint{
	logPallocChunkPages + 3*summaryLevelBits,
	logPallocChunkPages + 2*summaryLevelBits,
	logPallocChunkPages + 1*summaryLevelBits,
	logPallocChunkPages,
}

// 有关详细信息，请参阅mpagealloc64bit.go。
func (p *pageAlloc) sysInit() {
	// 计算所有条目将占用多少内存。
	// 
	// 这应该是大约12千磅或更少。
	totalSize := uintptr(0)
	for l := 0; l < summaryLevels; l++ {
		totalSize += (uintptr(1) << (heapAddrBits - levelShift[l])) * pallocSumBytes
	}
	totalSize = alignUp(totalSize, physPageSize)

	// 一次性为所有级别保留内存。32位应该不会有太多。没有多少。只需将其映射并标记为立即使用即可。
	reservation := sysReserve(nil, totalSize)
	if reservation == nil {
		throw("failed to reserve page summary memory")
	}
	sysMap(reservation, totalSize, p.sysStat)
	sysUsed(reservation, totalSize)

	// 迭代保留并将其切成片。
	// 
	// 将i作为从保留开始的字节偏移量，其中
	// 新片应开始。
	for l, shift := range levelShift {
		entries := 1 << (heapAddrBits - shift)

		// 将此保留放入一个切片中。
		sl := notInHeapSlice{(*notInHeap)(reservation), 0, entries}
		p.summary[l] = *(*[]pallocSum)(unsafe.Pointer(&sl))

		reservation = add(reservation, uintptr(entries)*pallocSumBytes)
	}
}

// 有关详细信息，请参阅mpagealloc64bit.go。
func (p *pageAlloc) sysGrow(base, limit uintptr) {
	if base%pallocChunkBytes != 0 || limit%pallocChunkBytes != 0 {
		print("runtime: base = ", hex(base), ", limit = ", hex(limit), "\n")
		throw("sysGrow bounds not aligned to pallocChunkBytes")
	}

	// 走到树上并更新摘要切片。
	for l := len(p.summary) - 1; l >= 0; l-- {
		// 找出这个新地址空间需要的摘要数组的哪一部分。
		// 注意，我们需要将范围与该级别的块宽度（1<<levelBits[l]）对齐，因为需要完整的块来计算下一级别的
		// 的摘要。
		lo, hi := addrsToSummaryRange(l, base, limit)
		_, hi = blockAlignSummaryRange(l, lo, hi)
		if hi > len(p.summary[l]) {
			p.summary[l] = p.summary[l][:hi]
		}
	}
}
